#include <cstddef>
#include <rockchip/mpp_frame.h>
#include <stdio.h>
#include <vector>
using namespace std;
#include "mpp_common.h"
#include "mpp_itc_enc_interface.h"

#include <rockchip/rk_mpi.h>
#include <rockchip/mpp_buffer.h>

#include <rockchip/mpp_buffer.h>
#include "rockchip/osal/mpp_env.h"
#include "rockchip/osal/mpp_mem.h"
#include "rockchip/osal/mpp_log.h"
#include "rockchip/osal/mpp_time.h"
#include "rockchip/osal/mpp_common.h"
#include "rockchip/osal/mpp_log.h"
#include "rockchip/utils/utils.h"
#include "rockchip/utils/mpi_enc_utils.h"
#include "rockchip/utils/camera_source.h"
class mpp_encode
{
    public:
        mpp_encode();
        ~mpp_encode();
        RET_CODE mpp_encode_init(const uint32_t height,const uint32_t width,
                const CODE_TYPE type,const FRAME_TYPE frame,
                ENC_CONFIG *config);
        RET_CODE mpp_encode_I_frame();
        RET_CODE mpp_encode_push(uint8_t *data,uint32_t length);
        RET_CODE mpp_encode_deinit();
        void  mpp_encode_done_register(mpp_enc_callback callback);
    private:
        RET_CODE mpp_encode_cfg_setup();
        RET_CODE fill_image(uint8_t *input_data,uint8_t *output_data,
                uint32_t width,uint32_t height,
                uint32_t hor_stride,uint32_t ver_stride,MppFrameFormat fmt);
        vector<mpp_enc_callback> mCallback;
        uint32_t width;
        uint32_t height;
        uint32_t hor_stride;
        uint32_t ver_stride;
        MppCodingType type;
        uint32_t num_frames;
        uint32_t loop_times;
        CamSource *cam_ctx;
        MppFrameFormat fmt;


        // resources
        size_t header_size;
        size_t frame_size;
        /* NOTE: packet buffer may overflow */
        size_t packet_size;

        uint32_t osd_enable;
        uint32_t osd_mode;
        uint32_t split_mode;
        uint32_t split_arg;

        uint32_t user_data_enable;
        uint32_t roi_enable;


        // base flow context
        MppCtx ctx;
        MppApi *mpi;
        MppEncCfg cfg;
        MppEncPrepCfg prep_cfg;
        MppEncRcCfg rc_cfg;
        MppEncCodecCfg codec_cfg;
        MppEncSliceSplit split_cfg;
        MppEncOSDPltCfg osd_plt_cfg;
        MppEncOSDPlt    osd_plt;
        MppEncOSDData   osd_data;
        MppEncROIRegion roi_region[3];
        MppEncROICfg    roi_cfg;

        // input / output
        MppBufferGroup buf_grp;
        MppBuffer frm_buf;
        MppBuffer pkt_buf;
        MppEncSeiMode sei_mode;
        MppEncHeaderMode header_mode;


        uint32_t bps;
        uint32_t bps_max;
        uint32_t bps_min;
        MppEncRcMode rc_mode;
        uint32_t gop_mode;
        uint32_t gop_len;
        uint32_t vi_len;
        uint32_t fps;



};

mpp_encode::mpp_encode():width(0),
    height(0),
    hor_stride(0),
    ver_stride(0),
    type(MPP_VIDEO_CodingAVC),
    num_frames(0),
    loop_times(0),
    cam_ctx(NULL),
    fmt(MPP_FMT_YUV420SP),
    header_size(0),
    frame_size(0),
    packet_size(0),
    osd_enable(0),
    osd_mode(0),
    split_arg(0),

    user_data_enable(0),
    roi_enable(0),
    ctx(NULL),
    mpi(NULL),

    buf_grp(NULL),
    frm_buf(NULL),
    pkt_buf(NULL),
    sei_mode(MPP_ENC_SEI_MODE_DISABLE),
    header_mode(MPP_ENC_HEADER_MODE_DEFAULT),

    bps(0),
    bps_max(0),
    bps_min(0),
    rc_mode(MPP_ENC_RC_MODE_CBR),

    gop_len(0),
    fps(0)
{
    mCallback.clear();
}
mpp_encode::~mpp_encode()
{
    mCallback.clear();

}
RET_CODE mpp_encode::mpp_encode_I_frame()
{
    return MPP_RET_CODE_OK;
}
RET_CODE mpp_encode::mpp_encode_deinit()
{
    int ret  = 0;
    ret = this->mpi->reset(this->ctx);
    if (ret) {
        mpp_err("mpi->reset failed\n");
    }

    if (this->ctx) {
        mpp_destroy(this->ctx);
        this->ctx = NULL;
    }

    if (this->cfg) {
        mpp_enc_cfg_deinit(this->cfg);
        this->cfg = NULL;
    }

    if (this->frm_buf) {
        mpp_buffer_put(this->frm_buf);
        this->frm_buf = NULL;
    }

    if (this->pkt_buf) {
        mpp_buffer_put(this->pkt_buf);
        this->pkt_buf = NULL;
    }

    if (this->osd_data.buf) {
        mpp_buffer_put(this->osd_data.buf);
        this->osd_data.buf = NULL;
    }

    if (this->buf_grp) {
        mpp_buffer_group_put(this->buf_grp);
        this->buf_grp = NULL;
    }



    return MPP_RET_CODE_OK;
}
void  mpp_encode::mpp_encode_done_register(mpp_enc_callback callback)
{
    mCallback.push_back(callback);
}
RET_CODE mpp_encode::mpp_encode_cfg_setup()
{
    MPP_RET ret;
    MppApi *mpi;
    MppCtx ctx;
    MppEncCfg cfg;
    RK_U32 gop_mode = this->gop_mode;

    mpi = this->mpi;
    ctx = this->ctx;
    cfg = this->cfg;

    mpp_enc_cfg_set_s32(cfg, "prep:width", this->width);
    mpp_enc_cfg_set_s32(cfg, "prep:height", this->height);
    mpp_enc_cfg_set_s32(cfg, "prep:hor_stride", this->hor_stride);
    mpp_enc_cfg_set_s32(cfg, "prep:ver_stride", this->ver_stride);
    mpp_enc_cfg_set_s32(cfg, "prep:format", this->fmt);

    mpp_enc_cfg_set_s32(cfg, "rc:mode", this->rc_mode);
    /* fix input / output frame rate */
    mpp_enc_cfg_set_s32(cfg, "rc:fps_in_flex", 0);        //--固定输入帧率
    mpp_enc_cfg_set_s32(cfg, "rc:fps_in_num", this->fps); //--表示输入帧率分数值的分子部分，如为 0 表示默认 30fps
    mpp_enc_cfg_set_s32(cfg, "rc:fps_in_denorm", 0);      //--表示输入帧率分数值的分母部分。如为 0 表示为 1
    mpp_enc_cfg_set_s32(cfg, "rc:fps_out_flex", 0);      //--表示输出帧率是否可变的标志位，默认为 0。
    mpp_enc_cfg_set_s32(cfg, "rc:fps_out_num",this->fps);//--表示输出帧率分数值的分子部分，如为 0 表示默认 30fps
    mpp_enc_cfg_set_s32(cfg, "rc:fps_out_denorm", 0);    //--表示输出帧率分数值的分母部分。如为 0 表示为 1
    mpp_enc_cfg_set_s32(cfg, "rc:gop", this->gop_len ? this->gop_len : this->fps * 2); //--设置I帧间隔

    /* drop frame or not when bitrate overflow */
    mpp_enc_cfg_set_u32(cfg, "rc:drop_mode", MPP_ENC_RC_DROP_FRM_DISABLED);
    mpp_enc_cfg_set_u32(cfg, "rc:drop_thd", 20);        /* 20% of max bps */
    mpp_enc_cfg_set_u32(cfg, "rc:drop_gap", 1);         /* Do not continuous drop frame */

    /* setup bitrate for different rc_mode */
    mpp_enc_cfg_set_s32(cfg, "rc:bps_target", this->bps);
    switch (this->rc_mode) {
        case MPP_ENC_RC_MODE_FIXQP : {
                                         /* do not setup bitrate on FIXQP mode */
                                     } break;
        case MPP_ENC_RC_MODE_CBR : {
                                       /* CBR mode has narrow bound */
                                       mpp_enc_cfg_set_s32(cfg, "rc:bps_max", this->bps_max ? this->bps_max : this->bps * 17 / 16);
                                       mpp_enc_cfg_set_s32(cfg, "rc:bps_min", this->bps_min ? this->bps_min : this->bps * 15 / 16);
                                   } break;
        case MPP_ENC_RC_MODE_VBR :
        case MPP_ENC_RC_MODE_AVBR : {
                                        /* VBR mode has wide bound */
                                        mpp_enc_cfg_set_s32(cfg, "rc:bps_max", this->bps_max ? this->bps_max : this->bps * 17 / 16);
                                        mpp_enc_cfg_set_s32(cfg, "rc:bps_min", this->bps_min ? this->bps_min : this->bps * 1 / 16);
                                    } break;
        default : {
                      /* default use CBR mode */
                      mpp_enc_cfg_set_s32(cfg, "rc:bps_max", this->bps_max ? this->bps_max : this->bps * 17 / 16);
                      mpp_enc_cfg_set_s32(cfg, "rc:bps_min", this->bps_min ? this->bps_min : this->bps * 15 / 16);
                  } break;
    }

    /* setup qp for different codec and rc_mode */
    switch (this->type) {
        case MPP_VIDEO_CodingAVC :
        case MPP_VIDEO_CodingHEVC : {
                                        switch (this->rc_mode) {
                                            case MPP_ENC_RC_MODE_FIXQP : {
                                                                             mpp_enc_cfg_set_s32(cfg, "rc:qp_init", 20);
                                                                             mpp_enc_cfg_set_s32(cfg, "rc:qp_max", 20);
                                                                             mpp_enc_cfg_set_s32(cfg, "rc:qp_min", 20);
                                                                             mpp_enc_cfg_set_s32(cfg, "rc:qp_max_i", 20);
                                                                             mpp_enc_cfg_set_s32(cfg, "rc:qp_min_i", 20);
                                                                             mpp_enc_cfg_set_s32(cfg, "rc:qp_ip", 2);
                                                                         } break;
                                            case MPP_ENC_RC_MODE_CBR :
                                            case MPP_ENC_RC_MODE_VBR :
                                            case MPP_ENC_RC_MODE_AVBR : {
                                                                            mpp_enc_cfg_set_s32(cfg, "rc:qp_init", 26);
                                                                            mpp_enc_cfg_set_s32(cfg, "rc:qp_max", 51);
                                                                            mpp_enc_cfg_set_s32(cfg, "rc:qp_min", 10);
                                                                            mpp_enc_cfg_set_s32(cfg, "rc:qp_max_i", 51);
                                                                            mpp_enc_cfg_set_s32(cfg, "rc:qp_min_i", 10);
                                                                            mpp_enc_cfg_set_s32(cfg, "rc:qp_ip", 2);
                                                                        } break;
                                            default : {
                                                          mpp_err_f("unsupport encoder rc mode %d\n", this->rc_mode);
                                                      } break;
                                        }
                                    } break;
        case MPP_VIDEO_CodingVP8 : {
                                       /* vp8 only setup base qp range */
                                       mpp_enc_cfg_set_s32(cfg, "rc:qp_init", 40);
                                       mpp_enc_cfg_set_s32(cfg, "rc:qp_max",  127);
                                       mpp_enc_cfg_set_s32(cfg, "rc:qp_min",  0);
                                       mpp_enc_cfg_set_s32(cfg, "rc:qp_max_i", 127);
                                       mpp_enc_cfg_set_s32(cfg, "rc:qp_min_i", 0);
                                       mpp_enc_cfg_set_s32(cfg, "rc:qp_ip", 6);
                                   } break;
        case MPP_VIDEO_CodingMJPEG : {
                                         /* jpeg use special codec config to control qtable */
                                         mpp_enc_cfg_set_s32(cfg, "jpeg:q_factor", 80);
                                         mpp_enc_cfg_set_s32(cfg, "jpeg:qf_max", 99);
                                         mpp_enc_cfg_set_s32(cfg, "jpeg:qf_min", 1);
                                     } break;
        default : {
                  } break;
    }
    /* setup codec  */
    mpp_enc_cfg_set_s32(cfg, "codec:type", this->type);
    switch (this->type) {
        case MPP_VIDEO_CodingAVC : {
                                       /*
                                        * H.264 profile_idc parameter
                                        * 66  - Baseline profile
                                        * 77  - Main profile
                                        * 100 - High profile
                                        */
                                       mpp_enc_cfg_set_s32(cfg, "h264:profile", 100);
                                       /*
                                        * H.264 level_idc parameter
                                        * 10 / 11 / 12 / 13    - qcif@15fps / cif@7.5fps / cif@15fps / cif@30fps
                                        * 20 / 21 / 22         - cif@30fps / half-D1@@25fps / D1@12.5fps
                                        * 30 / 31 / 32         - D1@25fps / 720p@30fps / 720p@60fps
                                        * 40 / 41 / 42         - 1080p@30fps / 1080p@30fps / 1080p@60fps
                                        * 50 / 51 / 52         - 4K@30fps
                                        */
                                       mpp_enc_cfg_set_s32(cfg, "h264:level", 40);
                                       mpp_enc_cfg_set_s32(cfg, "h264:cabac_en", 1);
                                       mpp_enc_cfg_set_s32(cfg, "h264:cabac_idc", 0);
                                       mpp_enc_cfg_set_s32(cfg, "h264:trans8x8", 1);
                                   } break;
        case MPP_VIDEO_CodingHEVC :
        case MPP_VIDEO_CodingMJPEG :
        case MPP_VIDEO_CodingVP8 : {
                                   } break;
        default : {
                      mpp_err_f("unsupport encoder coding type %d\n", this->type);
                  } break;
    }
    this->split_mode = 0;
    this->split_arg = 0;

    mpp_env_get_u32("split_mode", &this->split_mode, MPP_ENC_SPLIT_NONE);
    mpp_env_get_u32("split_arg", &this->split_arg, 0);

    if (this->split_mode) {
        mpp_log("%p split_mode %d split_arg %d\n", ctx, this->split_mode, this->split_arg);
        mpp_enc_cfg_set_s32(cfg, "split:mode", this->split_mode);
        mpp_enc_cfg_set_s32(cfg, "split:arg", this->split_arg);
    }
    ret = mpi->control(ctx, MPP_ENC_SET_CFG, cfg);
    if (ret) {
        mpp_err("mpi control enc set cfg failed ret %d\n", ret);
        goto RET;
    }
    /* optional */
    this->sei_mode = MPP_ENC_SEI_MODE_ONE_FRAME;
    ret = mpi->control(ctx, MPP_ENC_SET_SEI_CFG, &this->sei_mode);
    if (ret) {
        mpp_err("mpi control enc set sei cfg failed ret %d\n", ret);
        goto RET;
    }

    if (this->type == MPP_VIDEO_CodingAVC || this->type == MPP_VIDEO_CodingHEVC) {
        this->header_mode = MPP_ENC_HEADER_MODE_EACH_IDR;
        ret = mpi->control(ctx, MPP_ENC_SET_HEADER_MODE, &this->header_mode);
        if (ret) {
            mpp_err("mpi control enc set header mode failed ret %d\n", ret);
            goto RET;
        }
    }



    mpp_env_get_u32("gop_mode", &gop_mode, gop_mode);
    if (gop_mode) {
        MppEncRefCfg ref;

        mpp_enc_ref_cfg_init(&ref);

        if (this->gop_mode < 4)
            mpi_enc_gen_ref_cfg(ref, gop_mode);
        else
            mpi_enc_gen_smart_gop_ref_cfg(ref, this->gop_len, this->vi_len);

        ret = mpi->control(ctx, MPP_ENC_SET_REF_CFG, ref);
        if (ret) {
            mpp_err("mpi control enc set ref cfg failed ret %d\n", ret);
            goto RET;
        }
        mpp_enc_ref_cfg_deinit(&ref);
    }

    /* setup test mode by env */
    mpp_env_get_u32("osd_enable", &this->osd_enable, 0);
    mpp_env_get_u32("osd_mode", &this->osd_mode, MPP_ENC_OSD_PLT_TYPE_DEFAULT);
    mpp_env_get_u32("roi_enable", &this->roi_enable, 0);
    mpp_env_get_u32("user_data_enable", &this->user_data_enable, 0);
    return MPP_RET_CODE_OK;
RET:
    return MPP_RET_CODE_FAILURE;
}
RET_CODE mpp_encode::mpp_encode_init(const uint32_t height, const uint32_t width, 
        const CODE_TYPE type, const FRAME_TYPE frame, ENC_CONFIG *config)
{
    int ret = 0;
    MppPollType timeout = MPP_POLL_BLOCK;
    this->width = width;
    this->height=height;
    this->hor_stride = (MPP_ALIGN(width, 16));
    this->hor_stride = (MPP_ALIGN(height, 16));
    this->fps =config->fps;

    switch (frame)
    {
        case MPP_FRAME_TYPE_YUV420SP:     /* YYYY... UV... (NV12)     */
            fmt= MPP_FMT_YUV420SP;
            break;
        case MPP_FRAME_TYPE_YUV422:       /* YYYY... UVUV... (NV16)   */
            fmt=MPP_FMT_YUV422SP;
            break;
        case MPP_FRAME_TYPE_YUV420SP_VU:  /* YYYY... VUVUVU... (NV21) */
            fmt=MPP_FMT_YUV420SP_VU;
            break;
        case MPP_FRAME_TYPE_YUV422SP_VU:  /* YYYY... VUVUVU... (NV61) */
            fmt=MPP_FMT_YUV422SP_VU;
            break;
        case MPP_FRAME_TYPE_YUV422P:      /* YYYY... UU...VV...(422P) */
            fmt=MPP_FMT_YUV422P;
            break;

        default:
            return MPP_RET_CODE_FAILURE;
    }

    switch (type)
    {
        case MPP_TYPE_H264:
            this->type = MPP_VIDEO_CodingAVC;
            break;
        case MPP_TYPE_H265:
            this->type = MPP_VIDEO_CodingHEVC;
            break;
        case MPP_TYPE_MJPEG:
            this->type= MPP_VIDEO_CodingMJPEG;
            break;
        case MPP_TYPE_FAILURE:
        default:
            return MPP_RET_CODE_FAILURE;
    }

    bps = config->bps_cbr;
    bps_min = config->bps_vbr_min;
    bps_max = config->bps_vbr_max;

    switch (config->mode)
    {
        case ENCODE_RC_MODE_VBR:
            this->rc_mode = MPP_ENC_RC_MODE_VBR;
            break;
        case ENCODE_RC_MODE_CBR:
            this->rc_mode = MPP_ENC_RC_MODE_CBR;
            break;
        case ENCODE_RC_MODE_FIXQP:
            this->rc_mode = MPP_ENC_RC_MODE_FIXQP;
            break;
        case ENCODE_RC_MODE_AVBR:
            this->rc_mode = MPP_ENC_RC_MODE_AVBR;
            break;

        default:
            return MPP_RET_CODE_FAILURE;
    }
    //this->num_frames = 
    this->gop_len = config->gop;

    switch (this->fmt & MPP_FRAME_FMT_MASK)
    {
        case MPP_FMT_YUV420SP:
        case MPP_FMT_YUV420P: {
                                  this->frame_size = MPP_ALIGN(this->hor_stride, 64) * MPP_ALIGN(this->ver_stride, 64) * 3 / 2;
                              } break;

        case MPP_FMT_YUV422_YUYV :
        case MPP_FMT_YUV422_YVYU :
        case MPP_FMT_YUV422_UYVY :
        case MPP_FMT_YUV422_VYUY :
        case MPP_FMT_YUV422P :
        case MPP_FMT_YUV422SP :
        case MPP_FMT_RGB444 :
        case MPP_FMT_BGR444 :
        case MPP_FMT_RGB555 :
        case MPP_FMT_BGR555 :
        case MPP_FMT_RGB565 :
        case MPP_FMT_BGR565 : {
                                  this->frame_size = MPP_ALIGN(this->hor_stride, 64) * MPP_ALIGN(this->ver_stride, 64) * 2;
                              } break;

        default: {
                     this->frame_size = MPP_ALIGN(this->hor_stride, 64) * MPP_ALIGN(this->ver_stride, 64) * 4;
                 } break;
    }

    if (MPP_FRAME_FMT_IS_FBC(this->fmt))
        this->header_size = MPP_ALIGN(MPP_ALIGN(this->width, 16) * MPP_ALIGN(this->height, 16) / 16, SZ_4K);
    else
        this->header_size = 0;

    ret = mpp_buffer_group_get_internal(&buf_grp, MPP_BUFFER_TYPE_DRM);
    if (ret) {
        mpp_err_f("failed to get mpp buffer group ret %d\n", ret);
        goto MPP_ERR_OUT;
    }
    ret = mpp_buffer_get(buf_grp, &frm_buf, frame_size + header_size);
    if (ret) {
        mpp_err_f("failed to get buffer for input frame ret %d\n", ret);
        goto MPP_ERR_OUT;
    }

    ret = mpp_buffer_get(buf_grp, &pkt_buf, frame_size);
    if (ret) {
        mpp_err_f("failed to get buffer for output packet ret %d\n", ret);
        goto MPP_ERR_OUT;
    }

    ret = mpp_create(&this->ctx, &this->mpi);
    if (ret) {
        mpp_err("mpp_create failed ret %d\n", ret);
        goto MPP_ERR_OUT;
    }
    mpp_log("%p mpi_enc_test encoder test start w %d h %d type %d\n",
            this->ctx, this->width, this->height, this->type);

    ret = this->mpi->control(this->ctx, MPP_SET_OUTPUT_TIMEOUT, &timeout);
    if (MPP_OK != ret) {
        mpp_err("mpi control set output timeout %d ret %d\n", timeout, ret);
        goto MPP_ERR_OUT;
    }
    ret = mpp_init(this->ctx, MPP_CTX_ENC, this->type);
    if (ret) {
        mpp_err("mpp_init failed ret %d\n", ret);
        goto MPP_ERR_OUT;
    }

    ret = mpp_enc_cfg_init(&this->cfg);
    if (ret) {
        mpp_err_f("mpp_enc_cfg_init failed ret %d\n", ret);
        goto MPP_ERR_OUT;
    }

    ret = mpp_encode_cfg_setup();
    if (ret) {
        mpp_err_f("test mpp setup failed ret %d\n", ret);
        goto MPP_ERR_OUT;
    }

#if 0
    if (this->type == MPP_VIDEO_CodingAVC || this->type == MPP_VIDEO_CodingHEVC) {
        MppPacket packet = NULL;
        /*
         * Can use packet with normal malloc buffer as input not pkt_buf.
         * Please refer to vpu_api_legacy.cpp for normal buffer case.
         * Using pkt_buf buffer here is just for simplifing demo.
         */
        mpp_packet_init_with_buffer(&packet, this->pkt_buf);
        /* NOTE: It is important to clear output packet length!! */
        mpp_packet_set_length(packet, 0);

        ret = mpi->control(this->ctx, MPP_ENC_GET_HDR_SYNC, packet);
        if (ret) {
            mpp_err("mpi control enc get extra info failed\n");
            goto MPP_ERR_OUT;
        } else {
            /* get and write sps/pps for H.264 */
            void *ptr   = mpp_packet_get_pos(packet);
            size_t len  = mpp_packet_get_length(packet);
        }

        mpp_packet_deinit(&packet);
    }
#endif
    return MPP_RET_CODE_OK;
MPP_ERR_OUT:
    if (MPP_OK == ret){

    }
    else
        mpp_err("%p mpi_enc_test failed ret %d\n", this->ctx, ret);

    if (this->ctx) {
        mpp_destroy(this->ctx);
        this->ctx = NULL;
    }

    if (this->cfg) {
        mpp_enc_cfg_deinit(this->cfg);
        this->cfg = NULL;
    }

    if (this->frm_buf) {
        mpp_buffer_put(this->frm_buf);
        this->frm_buf = NULL;
    }

    if (this->pkt_buf) {
        mpp_buffer_put(this->pkt_buf);
        this->pkt_buf = NULL;
    }

    if (this->osd_data.buf) {
        mpp_buffer_put(this->osd_data.buf);
        this->osd_data.buf = NULL;
    }

    if (this->buf_grp) {
        mpp_buffer_group_put(this->buf_grp);
        this->buf_grp = NULL;
    }
    return MPP_RET_CODE_FAILURE;
}
RET_CODE mpp_encode::fill_image(uint8_t *input_data,uint8_t *output_data,
        uint32_t width,uint32_t height,
        uint32_t hor_stride,uint32_t ver_stride,MppFrameFormat fmt)
{

    return MPP_RET_CODE_OK;
}
RET_CODE mpp_encode::mpp_encode_push(uint8_t *data, uint32_t length)
{
    MPP_RET ret = MPP_SUCCESS;

    MppMeta meta = NULL;
    MppFrame frame = NULL;
    MppPacket packet = NULL;
    void *buf = mpp_buffer_get_ptr(this->frm_buf);
    RK_S32 cam_frm_idx = -1;
    MppBuffer cam_buf = NULL;
    RK_U32 eoi = 1;



    if(data==NULL || length<=0)
        return MPP_RET_CODE_FAILURE;

    memcpy(buf,data,length);


    ret = mpp_frame_init(&frame);
    if (ret) {
        mpp_err_f("mpp_frame_init failed\n");
        goto RET;
    }

    mpp_frame_set_width(frame, this->width);
    mpp_frame_set_height(frame, this->height);
    mpp_frame_set_hor_stride(frame, this->hor_stride);
    mpp_frame_set_ver_stride(frame, this->ver_stride);
    mpp_frame_set_fmt(frame, this->fmt);
    mpp_frame_set_eos(frame, 0);

    mpp_frame_set_buffer(frame, this->frm_buf);

    mpp_packet_init_with_buffer(&packet, this->pkt_buf);
    /* NOTE: It is important to clear output packet length!! */
    mpp_packet_set_length(packet, 0);
    mpp_meta_set_packet(meta, KEY_OUTPUT_PACKET, packet);


    //这里需要的话可以添加osd数据
    ret = mpi->encode_put_frame(ctx, frame);
    if (ret) {
        mpp_err("mpp encode put frame failed\n");
        mpp_frame_deinit(&frame);
        goto RET;
    }
    mpp_frame_deinit(&frame);
    while(!eoi){
        ret = mpi->encode_get_packet(ctx, &packet);
        if (ret) {
            mpp_err("mpp encode get packet failed\n");
            goto RET;
        }

        mpp_assert(packet);

        if(packet){
            void *ptr = mpp_packet_get_pos(packet);
            size_t len = mpp_packet_get_length(packet);
            //回调
             if (mpp_packet_is_partition(packet)) {
                    eoi = mpp_packet_is_eoi(packet);

                }
            mpp_packet_deinit(&packet);
        }
    }
    return MPP_RET_CODE_OK;
RET:
    return MPP_RET_CODE_FAILURE;
}
void enc_test()
{
    printf("NexyHo enc_test\n");
}

RET_CODE mpp_encode_init(void *cxt,
        const uint32_t height,const uint32_t width,
        const CODE_TYPE type,const FRAME_TYPE frame,
        ENC_CONFIG *config)
{
    return MPP_RET_CODE_OK;
}
RET_CODE mpp_encode_request_I_frame(void *cxt)
{
    return MPP_RET_CODE_OK;
}
void mpp_encode_done_register_callback(mpp_enc_callback callback)
{
}
RET_CODE mpp_encode_inpush(void *cxt,uint8_t *date,uint32_t length)
{
    return MPP_RET_CODE_OK;
}
RET_CODE mpp_encode_deinit(void *cxt)
{
    return MPP_RET_CODE_OK;
}







MPP_ITC_ENC_FUNTION * create_encode()
{
    MPP_ITC_ENC_FUNTION *fun = new MPP_ITC_ENC_FUNTION;
    if(fun){
        fun->mpp_enc_deinit=mpp_encode_deinit;
        fun->mpp_enc_done_register_callback = mpp_encode_done_register_callback;
        fun->mpp_enc_init=mpp_encode_init;
        fun->mpp_enc_inpush = mpp_encode_inpush;
        fun->mpp_enc_request_I_frame = mpp_encode_request_I_frame;
    }

    return fun;

}
void destroy(MPP_ITC_ENC_FUNTION * enc)
{
    if(enc){
        delete enc;
        enc = NULL;
    }
}















